package com.ruyuan.eshop.market.service.impl;

import com.ruyuan.eshop.common.enums.AmountTypeEnum;
import com.ruyuan.eshop.common.utils.ObjectUtil;
import com.ruyuan.eshop.common.utils.ParamCheckUtil;
import com.ruyuan.eshop.market.constants.MarketConstant;
import com.ruyuan.eshop.market.dao.CouponDAO;
import com.ruyuan.eshop.market.dao.FreightTemplateDAO;
import com.ruyuan.eshop.market.domain.dto.CalculateOrderAmountDTO;
import com.ruyuan.eshop.market.domain.entity.CouponDO;
import com.ruyuan.eshop.market.domain.entity.FreightTemplateDO;
import com.ruyuan.eshop.market.domain.request.CalculateOrderAmountRequest;
import com.ruyuan.eshop.market.exception.MarketBizException;
import com.ruyuan.eshop.market.exception.MarketErrorCodeEnum;
import com.ruyuan.eshop.market.service.MarketService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lxg
 * @Description:
 * @date 2022/3/2619:20
 */
@Service
public class MarketServiceImpl implements MarketService {
    @Autowired
    private CouponDAO couponDAO;

    @Autowired
    private FreightTemplateDAO freightTemplateDAO;
    /**
     * 计算订单费用
     *
     * 假设订单有两个商品条目记录，分摊优惠券的规则如下：
     * 商品1
     * 单价（单位分）    购买数量    小计
     * 1000            10         1000 * 10
     *
     * 商品2
     * 单价    购买数量    小计
     * 100    1         100 * 1
     *
     *
     * 整单优惠券抵扣5元，也就是500分
     *
     * 则商品1分摊的优惠券抵扣金额为：
     * 优惠券抵扣总额 * (商品1单价*商品1购买数量)/((商品1单价*商品1购买数量) + (商品2单价*商品2购买数量))
     * = 500 * (1000 * 10) / ((1000 * 10)  + (100 * 1) )
     * = 5000000 / 10100
     * = 495 分
     *
     * 同样的逻辑可计算出商品2分摊的优惠券抵扣金额为5分，也就是0.05元
     *
     *
     * 如果计算出的优惠券分摊到一条 item 上存在小数时，则向上取整，然后最后一条 item 分摊的金额就用优惠金额减掉前面所有优惠的item分摊的总额
     *
     *
     * @param calculateOrderAmountRequest 计算订单费用入参
     * @return
     */
    @Override
    public CalculateOrderAmountDTO calculateOrderAmount(CalculateOrderAmountRequest calculateOrderAmountRequest) {
        this.checkCalculateOrderAmountRequest(calculateOrderAmountRequest);
        String userId=calculateOrderAmountRequest.getUserId();
        String couponId=calculateOrderAmountRequest.getCouponId();
        String regionId=calculateOrderAmountRequest.getRegionId();
        String orderId=calculateOrderAmountRequest.getOrderId();
        // 优惠券抵扣金额
        Integer discountAmount=0;
        if (StringUtils.isNotBlank(couponId)){
            // 锁定优惠券
            CouponDO couponDO=getCouponAchieve(userId,couponId);
            discountAmount=couponDO.getAmount();
        }
        //原订单费用信息
        List<CalculateOrderAmountDTO.OrderAmountDTO> orderAmountDTOS = ObjectUtil.convertList(
                calculateOrderAmountRequest.getOrderAmountRequestList(), CalculateOrderAmountDTO.OrderAmountDTO.class, orderAmountDTO -> {
            orderAmountDTO.setOrderId(orderId);
        });
        //订单条目费用信息
        List<CalculateOrderAmountDTO.OrderAmountDetailDTO> orderAmountDetailDTOS = new ArrayList<>();
        List<CalculateOrderAmountRequest.OrderItemRequest> orderItemRequests=
                calculateOrderAmountRequest.
                getOrderItemRequestList();
        //全部商品价格
        int totalProductPrice=0;
        for (CalculateOrderAmountRequest.OrderItemRequest orderItemRequest : orderItemRequests) {
            totalProductPrice+=orderItemRequest.getSalePrice()*orderItemRequest.getSaleQuantity();
        }

        int index = 0;
        int totalNum = orderItemRequests.size();
        Integer notLastItemTotalDiscountAmount = 0;
        for (CalculateOrderAmountRequest.OrderItemRequest orderItemRequest : orderItemRequests) {
            //订单条目支付原价
            CalculateOrderAmountDTO.OrderAmountDetailDTO originPayAmountDetail=createOrderAmountDetailDTO(orderId,
                    AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode(), null, null, orderItemRequest);
            orderAmountDetailDTOS.add(originPayAmountDetail);
            //优惠卷抵扣金额
            CalculateOrderAmountDTO.OrderAmountDetailDTO couponDiscountAmountDetail;
            if (++index<totalNum){
                double partDiscountAmount=Integer.valueOf(discountAmount*orderItemRequest.getSaleQuantity()*orderItemRequest.getSalePrice()/Integer.valueOf(totalProductPrice)).doubleValue();
                // 遇到小数则向上取整
                double curDiscountAmount=Math.ceil(partDiscountAmount);
                couponDiscountAmountDetail=createOrderAmountDetailDTO(orderId,
                        AmountTypeEnum.COUPON_DISCOUNT_AMOUNT.getCode(), Double.valueOf(curDiscountAmount).intValue(), null, orderItemRequest);
                notLastItemTotalDiscountAmount+=couponDiscountAmountDetail.getAmount();
            }else{

                // 最后一条item的优惠金额等于总优惠金额-前面所有item分摊的优惠总额
                couponDiscountAmountDetail =
                        createOrderAmountDetailDTO(orderId,
                                AmountTypeEnum.COUPON_DISCOUNT_AMOUNT.getCode(),
                                discountAmount - notLastItemTotalDiscountAmount,
                                null,
                                orderItemRequest);
            }
            orderAmountDetailDTOS.add(couponDiscountAmountDetail);
            // 实付金额
            Integer realPayAmount = originPayAmountDetail.getAmount() - couponDiscountAmountDetail.getAmount();
            CalculateOrderAmountDTO.OrderAmountDetailDTO realPayAmountDetail =
                    createOrderAmountDetailDTO(orderId,
                            AmountTypeEnum.REAL_PAY_AMOUNT.getCode(),
                            null,
                            realPayAmount,
                            orderItemRequest);
            orderAmountDetailDTOS.add(realPayAmountDetail);
        }
        // 重新计算订单支付原价、优惠券抵扣金额、实付金额
        Integer totalOriginPayAmount = 0;
        Integer totalDiscountAmount = 0;
        Integer totalRealPayAmount = 0;
        for (CalculateOrderAmountDTO.OrderAmountDetailDTO orderAmountDetailDTO : orderAmountDetailDTOS) {
            Integer amountType = orderAmountDetailDTO.getAmountType();
            Integer amount = orderAmountDetailDTO.getAmount();
            if (AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode().equals(amountType)) {
                totalOriginPayAmount += amount;
            } else if (AmountTypeEnum.COUPON_DISCOUNT_AMOUNT.getCode().equals(amountType)) {
                totalDiscountAmount += amount;
            } else if (AmountTypeEnum.REAL_PAY_AMOUNT.getCode().equals(amountType)) {
                totalRealPayAmount += amount;
            }
        }
            // 总的实付金额还要加上运费
            Map<Integer, CalculateOrderAmountDTO.OrderAmountDTO> orderAmountDTOMap = orderAmountDTOS.stream().collect(Collectors.toMap(CalculateOrderAmountDTO.OrderAmountDTO::getAmountType, Function.identity()));
            //运费
            Integer shippingAmount = calculateOrderShippingAmount(regionId, orderAmountDTOMap);
            if (shippingAmount!=null){
                totalRealPayAmount+=shippingAmount;
            }
            for (CalculateOrderAmountDTO.OrderAmountDTO orderAmountDTO : orderAmountDTOS) {
                Integer amountType=orderAmountDTO.getAmountType();
                if(AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode().equals(amountType)) {
                    orderAmountDTO.setAmount(totalOriginPayAmount);
                } else if(AmountTypeEnum.COUPON_DISCOUNT_AMOUNT.getCode().equals(amountType)) {
                    orderAmountDTO.setAmount(totalDiscountAmount);
                } else if(AmountTypeEnum.REAL_PAY_AMOUNT.getCode().equals(amountType)) {
                    orderAmountDTO.setAmount(totalRealPayAmount);
                }
            }
        CalculateOrderAmountDTO calculateOrderAmountDTO = new CalculateOrderAmountDTO();
        calculateOrderAmountDTO.setOrderAmountList(orderAmountDTOS);
        calculateOrderAmountDTO.setOrderAmountDetail(orderAmountDetailDTOS);
        return calculateOrderAmountDTO;
    }

    private Integer calculateOrderShippingAmount(String regionId, Map<Integer, CalculateOrderAmountDTO.OrderAmountDTO> orderAmountDTOMap) {
        // 运费
        Integer shippingAmount;
        // 满多少免运费
        Integer conditionAmount;
        //查找运费模板
        FreightTemplateDO freightTemplateDO = freightTemplateDAO.getByRegionId(regionId);
        if(freightTemplateDO != null) {
            shippingAmount = freightTemplateDO.getShippingAmount();
            conditionAmount = freightTemplateDO.getConditionAmount();
        } else {
            shippingAmount = MarketConstant.DEFAULT_SHIPPING_AMOUNT;
            conditionAmount = MarketConstant.DEFAULT_CONDITION_AMOUNT;
        }
        // 订单金额
        Integer originPayAmount = 0;
        if(orderAmountDTOMap.get(AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode()) != null) {
            originPayAmount = orderAmountDTOMap.get(AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode()).getAmount();
        }
        // 如果原单金额大于指定值则免运费
        if(originPayAmount >= conditionAmount) {
            shippingAmount = 0;
        }
        return shippingAmount;
    }

    /**
     * 组装订单条目费用明细
     * @param orderId 订单号
     * @param amountType 费用类型
     * @param discountAmount 优惠券抵扣金额
     * @param realPayAmount 实付金额
     * @param orderItemRequest 订单条目
     * @return
     */
    private CalculateOrderAmountDTO.OrderAmountDetailDTO createOrderAmountDetailDTO(
            String orderId,
            Integer amountType,
            Integer discountAmount,
            Integer realPayAmount,
            CalculateOrderAmountRequest.OrderItemRequest orderItemRequest) {
        CalculateOrderAmountDTO.OrderAmountDetailDTO orderAmountDetailDTO
                = new CalculateOrderAmountDTO.OrderAmountDetailDTO();
        orderAmountDetailDTO.setOrderId(orderId);
        orderAmountDetailDTO.setAmountType(amountType);
        orderAmountDetailDTO.setSkuCode(orderItemRequest.getSkuCode());
        orderAmountDetailDTO.setProductType(orderItemRequest.getProductType());
        orderAmountDetailDTO.setSalePrice(orderItemRequest.getSalePrice());
        orderAmountDetailDTO.setSaleQuantity(orderItemRequest.getSaleQuantity());
        if (AmountTypeEnum.ORIGIN_PAY_AMOUNT.getCode().equals(amountType)){
            orderAmountDetailDTO.setAmount(orderItemRequest.getSalePrice()*orderItemRequest.getSaleQuantity());
        }else if (AmountTypeEnum.COUPON_DISCOUNT_AMOUNT.getCode().equals(amountType)){
            orderAmountDetailDTO.setAmount(discountAmount);
        }else if (AmountTypeEnum.REAL_PAY_AMOUNT.getCode().equals(amountType)){
            orderAmountDetailDTO.setAmount(realPayAmount);
        }
        return orderAmountDetailDTO;

    }

    private CouponDO getCouponAchieve(String userId, String couponId) {
        CouponDO couponDO=couponDAO.getUserCoupon(userId, couponId);
        if (couponDO==null){
            throw new MarketBizException(MarketErrorCodeEnum.USER_COUPON_IS_NULL);
        }
        return couponDO;
    }

    /**
     * 入参检查
     * @param calculateOrderAmountRequest
     */
    private void checkCalculateOrderAmountRequest(CalculateOrderAmountRequest calculateOrderAmountRequest){
        //订单id
        String orderNo=calculateOrderAmountRequest.getOrderId();
        ParamCheckUtil.checkStringNonEmpty(orderNo);
        //userId
        String userId=calculateOrderAmountRequest.getUserId();
        ParamCheckUtil.checkStringNonEmpty(userId);
        //订单商品条目id
        List<CalculateOrderAmountRequest.OrderItemRequest> orderItemRequestList = calculateOrderAmountRequest.getOrderItemRequestList();
        ParamCheckUtil.checkCollectionNonEmpty(orderItemRequestList);
        //订单费用信息
        List<CalculateOrderAmountRequest.OrderAmountRequest> orderAmountRequestList = calculateOrderAmountRequest.getOrderAmountRequestList();
        ParamCheckUtil.checkCollectionNonEmpty(orderAmountRequestList);

    }
}
